package it.polimi.traveldream.managers;

import it.polimi.traveldream.persistence.Hotel;
import it.polimi.traveldream.persistence.Pacchetto;
import it.polimi.traveldream.persistence.PonteHotelPacchetto;
import it.polimi.traveldream.persistence.PonteHotelPacchettoPK;
import it.polimi.traveldream.persistence.dtos.HotelProdDTO;

import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class ProductsAndPacchetsRelationsManagerImpl implements ProductsAndPacchetsRelationsManager {

	@PersistenceContext
	private EntityManager em;

	@EJB(beanName="ProductManagerImpl")
	private ProductManager productMgr;

	@EJB(beanName="PacchettoManagerImpl")
	private PacchettoManager pacchetMgr;

	private ProductManagerImpl getProductManager() {
		return (ProductManagerImpl) productMgr;
	}

	private PacchettoManagerImpl getPacchettoManager() {
		return (PacchettoManagerImpl) pacchetMgr;
	}

	@Override
	public List<HotelProdDTO> getHotelProductsInPacchetto(int pacchettoID) {
		Pacchetto pacchetto = getPacchettoManager().findPacchettoEntity(pacchettoID);
		List<PonteHotelPacchetto> ponte = pacchetto.getPonteHotelPacchettos();
		return ConverterFactory.convertList(ponte, new ConverterFactory.ConverterCallback<PonteHotelPacchetto, HotelProdDTO>() {

			@Override
			public HotelProdDTO autoConvert(PonteHotelPacchetto dto) {
				return getProductManager().convert(dto.getHotel());
			}
		});
	}

	@Override
	public void addHotelToPacchetto(int pacchettoID, int hotelID, int numeroPersone) {
		Pacchetto pacchetto = getPacchettoManager().findPacchettoEntity(pacchettoID);
		Hotel hotel = getProductManager().findHotelEntity(hotelID);
		PonteHotelPacchettoPK pk = new PonteHotelPacchettoPK();
		pk.setIDHotel(hotelID);
		pk.setIDPacchetto(pacchettoID);
		PonteHotelPacchetto ponte = new PonteHotelPacchetto();
		ponte.setId(pk);
		ponte.setNumeroPersone(numeroPersone);
		ponte.setHotel(hotel);
		ponte.setPacchetto(pacchetto);
		try {
			em.getTransaction().begin();
			// le parti commentate credo non servano, ma se qualcosa non va in questa parte
			// forse scommentandole potrebbe funzionare. Non ho ben capito JPA come gestisce queste liste
			//pacchetto.addPonteHotelPacchetto(ponte);
			//hotel.addPonteHotelPacchetto(ponte);
			em.persist(ponte);
			//em.merge(pacchetto);
			//em.merge(hotel);
			em.getTransaction().commit();
		} catch (Exception e) {
			em.getTransaction().rollback();
			throw new RuntimeException(e);
		}
	}

	@Override
	public void removeHotelFromPacchetto(int pacchettoID, int hotelID) {
		//Pacchetto pacchetto = getPacchettoManager().findPacchettoEntity(pacchettoID);
		//Hotel hotel = getProductManager().findHotelEntity(hotelID);
		PonteHotelPacchettoPK pk = new PonteHotelPacchettoPK();
		pk.setIDHotel(hotelID);
		pk.setIDPacchetto(pacchettoID);
		PonteHotelPacchetto ponte = em.find(PonteHotelPacchetto.class, pk);

		try {
			em.getTransaction().begin();
			// come sopra
			//pacchetto.removePonteHotelPacchetto(ponte);
			//hotel.removePonteHotelPacchetto(ponte);
			//em.merge(pacchetto);
			//em.merge(hotel);
			em.remove(ponte);
			em.getTransaction().commit();
		} catch (Exception e) {
			em.getTransaction().rollback();
			throw new RuntimeException(e);
		}
	}

	@Override
	public int getNumberOfPersonInHotel(int pacchettoID, int hotelID) {
		PonteHotelPacchettoPK pk = new PonteHotelPacchettoPK();
		pk.setIDHotel(hotelID);
		pk.setIDPacchetto(pacchettoID);
		PonteHotelPacchetto ponte = em.find(PonteHotelPacchetto.class, pk);
		return ponte.getNumeroPersone();
	}

	@Override
	public List<HotelProdDTO> getHotelProductsNotInPacchetto(int pacchettoID) {
		@SuppressWarnings("unchecked")
		List<Hotel> hotels = em.createNativeQuery("Select h FROM Hotel h WHERE "
				+ "h.ID NOT IN (SELECT p.IDPacchetto From PonteHotelPacchetto p WHERE p.IDPacchetto = "
				+ pacchettoID + ")", Hotel.class).getResultList();
		return ConverterFactory.convertList(hotels, new ConverterFactory.ConverterCallback<Hotel, HotelProdDTO>() {

			@Override
			public HotelProdDTO autoConvert(Hotel dto) {
				return getProductManager().convert(dto);
			}
		});
	}
}
